// obj的第一个field必须指向自身的meta描述数组, meta数组的第一个元素的size必须是自身数组的size.


// 使用注意事项:
// 结构体成员名称严格对应Json字串中的名称, 可以有非Json相关联的成员,只要meta描述中不出现即可.
// 结构体成员只有整数，整数指针, 字符数组(字符串), 字符串指针, float, float指针, cJSON指针, 数组, 数组指针, 子结构, 子结构指针11种
// 数组只支持整形，字符串指针(不知size, 只能利用cJSON的valuestring, 减少内存分配)，float，子结构四种
// 不支持数组嵌套数组, 其实不存在数组嵌套, 因为数组必须有count字段,这样子数组对C来说其实是一个Structure
// 数组必须前置一个整形成员记录数组大小(数组成员个数), 成对出现
// 定义结构避免大小正好=size_t, 否则会被当成结构指针处理
// 从json string构建结构体，只有数组有可能会分配内存，要caller主动释放。
// 建议使用前，结构自己先初始化。
// json转obj，除了字符串和数组两种动态大小的可以不分配内存, 其他种类的指针必须分配好内存.

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
#include "kg_json.h"

// function -----------------------------------------------------------------------------------------------

// from current meta(type position, not name position), find next meta
static meta_t* KgArrayGetNextMeta(const meta_t* metas)
{
    short tp;
    while ((tp = (short)*metas) != KJ_END) {
        metas++;
        if ((tp != KJ_OBJ) && (tp != KJ_POBJ) && (tp != KJ_LIST) && (tp != KJ_PLIST))
            break;
    }
    return (meta_t* )metas;
}

// return <0表示出错 cnt-数组大小，arr-指向数组，meta - meta，arr_type - type(普通数组)
int KgList2Json(cJSON* node, KJList* arr, const meta_t* meta)
{
    cJSON* sub = NULL;
    char buf[48];
    float margin;
    short tp = (short)(*meta);
    for (int i = 0; i < arr->cnt; i++) {
        switch (tp)
        {
        case KJ_PSTR:
            sub = cJSON_CreateString(((char**)(arr->list))[i]);
            if (sub == NULL) return -1;
            break;
        case KJ_CHAR:
            if (((char*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sub = cJSON_CreateNumber(((char*)(arr->list))[i]);
            if (sub == NULL) return -1;
            break;
        case KJ_BYTE:
            if (((uint8_t*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sub = cJSON_CreateNumber(((uint8_t*)(arr->list))[i]);
            if (sub == NULL) return -1;
            break;
        case KJ_SHORT:
            if (((short*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sub = cJSON_CreateNumber(((short*)(arr->list))[i]);
            if (sub == NULL) return -1;
            break;
        case KJ_USHORT:
            if (((uint16_t*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sub = cJSON_CreateNumber(((uint16_t*)(arr->list))[i]);
            if (sub == NULL) return -1;
            break;
        case KJ_INT:
            if (((int*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sub = cJSON_CreateNumber(((int*)(arr->list))[i]);
            if (sub == NULL) return -1;
            break;
        case KJ_INT_1:
            if (((int*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sub = cJSON_CreateNumber(((int*)(arr->list))[i] / 10);
            if (sub == NULL) return -1;
            break;
        case KJ_FLOAT:
            margin = ((float*)(arr->list))[i] - KJ_FLOAT_INVALID;
            if (margin > -0.00001 && margin < 0.00001) break;
            sub = cJSON_CreateNumber(((float*)(arr->list))[i]);
            if (sub == NULL) return -1;
            break;
        case KJ_INT_S:
            if (((int*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sprintf(buf, "%d", ((int*)(arr->list))[i]);
            sub = cJSON_CreateString(buf);
            if (sub == NULL) return -1;
            break;
        case KJ_INT_FS1:
            if (((int*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sprintf(buf, "%2.1f", (float)(((int*)(arr->list))[i]) / 10);
            sub = cJSON_CreateString(buf);
            if (sub == NULL) return -1;
            break;
        case KJ_INT_FS2:
            if (((int*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sprintf(buf, "%3.2f", (float)(((int*)(arr->list))[i]) / 100);
            sub = cJSON_CreateString(buf);
            if (sub == NULL) return -1;
            break;
        case KJ_INT_F1:
            if (((int*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sprintf(buf, "%2.1f", (float)(((int*)(arr->list))[i]) / 10);
            sub = cJSON_CreateRaw(buf);
            if (sub == NULL) return -1;
            break;
        case KJ_INT_F2:
            if (((int*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sprintf(buf, "%3.2f", (float)(((int*)(arr->list))[i]) / 100);
            sub = cJSON_CreateRaw(buf);
            if (sub == NULL) return -1;
            break;
        case KJ_INT_F3:
            if (((int*)(arr->list))[i] == KJ_DWORD_INVALID) break;
            sprintf(buf, "%4.3f", (float)(((int*)(arr->list))[i]) / 1000);
            sub = cJSON_CreateRaw(buf);
            if (sub == NULL) return -1;
            break;

        case KJ_OBJ: // 这是一个sub object, recursive call.
            // TODO
            break;
        case KJ_POBJ: // 这是一个sub object, recursive call.
            sub = cJSON_CreateObject();
            if (sub == NULL) return -1;
            if (KgStruct2Json(sub, ((void**)(arr->list))[i], (meta_t*)(*(meta + 1))) == -1)
                return -1;
            break;

        case KJ_LIST:
            sub = cJSON_CreateArray();
            if (sub == NULL) return -1;
            if (KgList2Json(sub, &(((KJList*)(arr->list))[i]), (meta_t*)(meta + 1)) == -1)
                return -1;
            break;
        case KJ_PLIST:
            sub = cJSON_CreateArray();
            if (sub == NULL) return -1;
            if (KgList2Json(sub, ((KJList**)(arr->list))[i], (meta_t*)(meta + 1)) == -1)
                return -1;
            break;
        case KJ_PJSON:
            sub = ((cJSON**)(arr->list))[i];
            break;
        default:
            return -1;
        }
        if (!cJSON_AddItemToArray(node, sub)) return -1;
    }
    return 0;
}
// Struct to json, node - current operate cjson node; st - struct instance point; metas - struct meta description stream
int KgStruct2Json(cJSON* node, void* st, const meta_t* metas)
{
    cJSON* sub = NULL;
    cJSON* raw;
    char buf[48];
    float margin;
    short tp;
    while ((tp = (short)*metas) != KJ_END) {
        int offset = (int)(*(metas++) >> 16);
        char* name = (char*)(*(metas++));
        // k_开头的名字，要去掉k_。专门对于自研项目, 协议json中要求name是005， 但是c语言变量要字母开头, 所以是：k_005
        if(name[0]=='k' && name[1]=='_') name += 2;
        // check this is point type or not, and find the true obj field location.
        void* field = NULL;
        if (tp == KJ_PSTR || tp == KJ_POBJ || tp == KJ_PJSON || tp == KJ_PLIST)
            field = *(void**)((char*)st + offset);
        else
            field = ((char*)st + offset);
        if (field == NULL) continue;
        switch (tp)
        {
        case KJ_PSTR:
            if (cJSON_AddStringToObject(node, name, (const char*)field) == NULL) return -1;
            break;
        case KJ_CHAR:
            if (*(char*)field == KJ_BYTE_INVALID) break;
            if (cJSON_AddNumberToObject(node, name, *(char*)field) == NULL) return -1;
            break;
        case KJ_BYTE:
            if (*(uint8_t*)field == KJ_BYTE_INVALID) break;
            if (cJSON_AddNumberToObject(node, name, *(uint8_t*)field) == NULL) return -1;
            break;
        case KJ_SHORT:
            if (*(int16_t*)field == KJ_WORD_INVALID) break;
            if (cJSON_AddNumberToObject(node, name, *(int16_t*)field) == NULL) return -1;
            break;
        case KJ_USHORT:
            if (*(uint16_t*)field == KJ_WORD_INVALID) break;
            if (cJSON_AddNumberToObject(node, name, *(uint16_t*)field) == NULL) return -1;
            break;
        case KJ_INT:
            if (*(int*)field == KJ_DWORD_INVALID) break;
            if (cJSON_AddNumberToObject(node, name, *(int*)field) == NULL) return -1;
            break;
        case KJ_INT_1:
            if (*(int*)field == KJ_DWORD_INVALID) break;
            if (cJSON_AddNumberToObject(node, name, *(int*)field / 10) == NULL) return -1;
            break;
        case KJ_FLOAT:
            margin = *(float*)field - KJ_FLOAT_INVALID;
            if (margin > -0.00001 && margin < 0.00001) break;
            if (cJSON_AddNumberToObject(node, name, *(float*)field) == NULL) return -1;
            break;
        case KJ_OBJ: // 这是一个sub object, recursive call.
            //sub = cJSON_CreateObject();
            //if (cJSON_AddItemToObject(node, name, sub))
            //    if (KgStruct2Json(sub, field, (meta_t*)(*(metas++))) != -1)
            //        break;
            //return -1;
        case KJ_POBJ: // 这是一个sub object pointer, recursive call.
            sub = cJSON_CreateObject();
            if (cJSON_AddItemToObject(node, name, sub))
                if (KgStruct2Json(sub, field, (meta_t*)(*(metas++))) != -1)
                    break;
            return -1;
        case KJ_LIST:
        case KJ_PLIST:
            sub = cJSON_CreateArray();
            if (cJSON_AddItemToObject(node, name, sub)) {
                if (KgList2Json(sub, field, metas) != -1) {
                    metas = KgArrayGetNextMeta(metas);
                    break;
                }
            }
            return -1;
        case KJ_PJSON:
            if (cJSON_AddItemToObject(node, name, (cJSON*)field)) break;
            return -1;
        case KJ_INT_S:
            if (*(int*)field == KJ_DWORD_INVALID) break;
            sprintf(buf, "%d", *(int*)field);
            if (cJSON_AddStringToObject(node, name, buf) == NULL) return -1;
            break;
        case KJ_INT_FS1:
            if (*(int*)field == KJ_DWORD_INVALID) break;
            sprintf(buf, "%2.1f", (float)(*(int*)field) / 10);
            if (cJSON_AddStringToObject(node, name, buf) == NULL) return -1;
            break;
        case KJ_INT_FS2:
            if (*(int*)field == KJ_DWORD_INVALID) break;
            sprintf(buf, "%3.2f", (float)(*(int*)field) / 100);
            if (cJSON_AddStringToObject(node, name, buf) == NULL) return -1;
            break;
        case KJ_INT_F1:
            if (*(int*)field == KJ_DWORD_INVALID) break;
            sprintf(buf, "%2.1f", ((float)(*(int*)field) / 10));
            raw = cJSON_CreateRaw(buf);
            if (!cJSON_AddItemToObject(node, name, raw)) return -1;
            break;
        case KJ_INT_F2:
            if (*(int*)field == KJ_DWORD_INVALID) break;
            sprintf(buf, "%3.2f", ((float)(*(int*)field) / 100));
            raw = cJSON_CreateRaw(buf);
            if (!cJSON_AddItemToObject(node, name, raw)) return -1;
            break;
        case KJ_INT_F3:
            if (*(int*)field == KJ_DWORD_INVALID) break;
            sprintf(buf, "%4.3f", ((float)(*(int*)field) / 1000));
            raw = cJSON_CreateRaw(buf);
            if (!cJSON_AddItemToObject(node, name, raw)) return -1;
            break;
        default:
            return -1;
        }
    }
    return 0;
}






int KgJson2List(cJSON* node, KJList* arr, const meta_t* meta)
{
    // cJSON *pSub = NULL;
    // char *pField = *(char **)(pMetas->pField);
    int cnt = cJSON_GetArraySize(node);
    cnt = (cnt > arr->cnt) ? arr->cnt : cnt;
    arr->cnt = 0;
    short tp = (short)(*meta);
    for (int i = 0; i < cnt; i++) {
        cJSON* item = cJSON_GetArrayItem(node, i);
        switch (tp)
        {
            //    case KJ_STR:
            //        if(item == NULL || cJSON_IsNull(item) || !cJSON_IsString(item)) 
            //            *(char *)field = '\0';
            //        else
            //            strncpy(field, item->valuestring, (metas->type >> 8) - 1);
            //        break;
        case KJ_PSTR:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsString(item)) ((char**)(arr->list))[i] = NULL;
            else ((char**)(arr->list))[i] = item->valuestring;
            break;
        case KJ_CHAR:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) ((char*)(arr->list))[i] = KJ_BYTE_INVALID;
            else ((char*)(arr->list))[i] = (char)item->valueint;
            break;
        case KJ_BYTE:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) ((uint8_t*)(arr->list))[i] = KJ_BYTE_INVALID;
            else ((uint8_t*)(arr->list))[i] = (uint8_t)item->valueint;
            break;
        case KJ_SHORT:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) ((int16_t*)(arr->list))[i] = KJ_WORD_INVALID;
            else ((int16_t*)(arr->list))[i] = (int16_t)item->valueint;
            break;
        case KJ_USHORT:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) ((uint16_t*)(arr->list))[i] = KJ_WORD_INVALID;
            else ((uint16_t*)(arr->list))[i] = (uint16_t)item->valueint;
            break;
        case KJ_INT:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            else ((int*)(arr->list))[i] = item->valueint;
            break;
        case KJ_INT_1:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            else ((int*)(arr->list))[i] = item->valueint * 10;
            break;
        case KJ_FLOAT:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) ((float*)(arr->list))[i] = KJ_FLOAT_INVALID;
            else ((float*)(arr->list))[i] = (float)item->valuedouble;
            break;

        case KJ_OBJ:
            // TODO
            break;
        case KJ_POBJ:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsObject(item)) break;
            if (KgJson2Struct(item, ((void**)(arr->list))[i], (meta_t*)*(meta + 1)) < 0) return -1;
            break;
        case KJ_PLIST:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsArray(item)) break;
            if (KgJson2List(item, ((KJList**)(arr->list))[i], meta + 1) < 0) return -1;
            meta = KgArrayGetNextMeta(meta);
            break;
        case KJ_LIST:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsArray(item)) break;
            if (KgJson2List(item, &((KJList*)(arr->list))[i], meta + 1) < 0) return -1;
            meta = KgArrayGetNextMeta(meta);
            break;
        case KJ_PJSON:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsObject(item)) ((cJSON**)(arr->list))[i] = NULL;
            else ((cJSON**)(arr->list))[i] = item;
            break;
        case KJ_INT_S:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsString(item))
                ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            else
                ((int*)(arr->list))[i] = atoi(item->valuestring);
            if (((int*)(arr->list))[i] == 0 && strcmp(item->valuestring, "0") != 0) ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            break;
        case KJ_INT_FS1:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsString(item))
                ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            else
                ((int*)(arr->list))[i] = (int)(atof(item->valuestring) * 10);
            if (((int*)(arr->list))[i] == 0 && strcmp(item->valuestring, "0") != 0 && strcmp(item->valuestring, "0.0") != 0) ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            break;
        case KJ_INT_FS2:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsString(item))
                ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            else
                ((int*)(arr->list))[i] = (int)(atof(item->valuestring) * 100);
            if (((int*)(arr->list))[i] == 0 && strcmp(item->valuestring, "0") != 0 && strcmp(item->valuestring, "0.00") != 0) ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            break;
        case KJ_INT_F1:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            else ((int*)(arr->list))[i] = (int)(item->valuedouble * 10);
            break;
        case KJ_INT_F2:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            else ((int*)(arr->list))[i] = (int)(item->valuedouble * 100);
            break;
        case KJ_INT_F3:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) ((int*)(arr->list))[i] = KJ_DWORD_INVALID;
            else ((int*)(arr->list))[i] = (int)(item->valuedouble * 1000);
            break;
        default:
            break;
        }
    }
    arr->cnt = cnt;
    return 0;
}

int KgJson2Struct(cJSON* node, void* st, const meta_t* metas)
{
    // float margin;
    short tp;
    while ((tp = (short)*metas) != KJ_END) {
        int offset = (int)(*(metas++) >> 16);
        char* name = (char*)(*(metas++));
        // k_开头的名字，要去掉k_。专门对于自研项目, 协议json中要求name是005， 但是c语言变量要字母开头, 所以是：k_005
        if(name[0]=='k' && name[1]=='_') name += 2;
        void* field = NULL;
        if (tp == KJ_PSTR || tp == KJ_POBJ || tp == KJ_PJSON || tp == KJ_PLIST)
            field = (void**)((char*)st + offset);
        else
            field = ((char*)st + offset);

        cJSON* item = cJSON_GetObjectItem(node, name);
        switch (tp)  // json转obj，除了字符串和数组两种动态大小的可以不分配内存, 其他种类的指针必须分配好内存.
        {
            // case KJ_STR:
            //     if(item == NULL || cJSON_IsNull(item) || !cJSON_IsString(item)) 
            //         *(char *)field = '\0';
            //     else
            //         strncpy(field, item->valuestring, (metas->type >> 8) - 1);
            //     break;
        case KJ_PSTR:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsString(item)) *(char**)field = NULL;
            else *(char**)field = item->valuestring;
            break;
        case KJ_CHAR:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) *(char*)field = KJ_BYTE_INVALID;
            else *(char*)field = (char)item->valueint;
            break;
        case KJ_BYTE:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) *(uint8_t*)field = KJ_BYTE_INVALID;
            else *(uint8_t*)field = (uint8_t)item->valueint;
            break;
        case KJ_SHORT:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) *(int16_t*)field = KJ_WORD_INVALID;
            else *(int16_t*)field = (int16_t)item->valueint;
            break;
        case KJ_USHORT:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) *(uint16_t*)field = KJ_WORD_INVALID;
            else *(uint16_t*)field = (uint16_t)item->valueint;
            break;
        case KJ_INT:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) *(int*)field = KJ_DWORD_INVALID;
            else *(int*)field = item->valueint;
            break;
        case KJ_INT_1:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) *(int*)field = KJ_DWORD_INVALID;
            else *(int*)field = item->valueint * 10;
            break;
        case KJ_FLOAT:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) *(float*)field = KJ_FLOAT_INVALID;
            else *(float*)field = (float)item->valuedouble;
            break;

        case KJ_OBJ:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsObject(item)) {  // 虽然json解析不出，但是metas要+1, 正确指向下一个
                metas++;
                break;
            }
            if (KgJson2Struct(item, field, (meta_t*)*(metas++)) < 0) return -1;
            break;
        case KJ_POBJ:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsObject(item)) {  // 虽然json解析不出，但是metas要+1, 正确指向下一个
                *(void**)field = NULL;
                metas++;
                break;
            }
            if (KgJson2Struct(item, *(void**)field, (meta_t*)*(metas++)) < 0) return -1;
            break;
        case KJ_LIST:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsArray(item)) break;
            if (KgJson2List(item, (KJList*)field, metas) < 0) return -1;
            metas = KgArrayGetNextMeta(metas);
            break;
        case KJ_PLIST:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsArray(item)) break;
            if (KgJson2List(item, *(KJList**)field, metas) < 0) return -1;
            metas = KgArrayGetNextMeta(metas);
            break;
        case KJ_PJSON:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsObject(item)) *(cJSON**)field = NULL;
            else *(cJSON**)field = item;
            break;
        case KJ_INT_S:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsString(item))
                *(int*)field = KJ_DWORD_INVALID;
            else
                *(int*)field = atoi(item->valuestring);
            if (*(int*)field == 0 && strcmp(item->valuestring, "0") != 0) *(int*)field = KJ_DWORD_INVALID;
            break;
        case KJ_INT_FS1:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsString(item))
                *(int*)field = KJ_DWORD_INVALID;
            else
                *(int*)field = (int)(atof(item->valuestring) * 10);
            if (*(int*)field == 0 && strcmp(item->valuestring, "0") != 0 && strcmp(item->valuestring, "0.0") != 0) *(int*)field = KJ_DWORD_INVALID;
            break;
        case KJ_INT_FS2:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsString(item))
                *(int*)field = KJ_DWORD_INVALID;
            else
                *(int*)field = (int)(atof(item->valuestring) * 100);
            if (*(int*)field == 0 && strcmp(item->valuestring, "0") != 0 && strcmp(item->valuestring, "0.00") != 0) *(int*)field = KJ_DWORD_INVALID;
            break;
        case KJ_INT_F1:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) *(int*)field = KJ_DWORD_INVALID;
            else *(int*)field = (int)(item->valuedouble * 10);
            break;
        case KJ_INT_F2:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) *(int*)field = KJ_DWORD_INVALID;
            else *(int*)field = (int)(item->valuedouble * 100);
            break;
        case KJ_INT_F3:
            if (item == NULL || cJSON_IsNull(item) || !cJSON_IsNumber(item)) *(int*)field = KJ_DWORD_INVALID;
            else *(int*)field = (int)(item->valuedouble * 1000);
            break;
        default:
            break;
        }
    }
    return 0;
}
meta_t* ZqMetasTrim(const meta_t *pOrgMeta, int cnt, const char *names[])
{
    int k = 0;
    unsigned char buf[256] = {0};
    if (cnt > 64) return NULL;     // 最多只处理64个数据

    for(int i = 0; i < cnt; i++){
        char *pName = (char *)names[i];
        meta_t *metas = (meta_t *)pOrgMeta;
        short tp = 0;
        while ((tp = (short)*metas) != KJ_END) {
            // int offset = (int)(*metas >> 16);
            char* name = (char*)(*(metas+1));
            int j = (metas - pOrgMeta);
            int x = 2;
            if (tp == KJ_OBJ || tp == KJ_POBJ)
                x++;
            else if (tp == KJ_LIST || tp == KJ_PLIST)
                x = KgArrayGetNextMeta(metas+x) - metas;
            metas += x;
            if (strcmp(pName, name) == 0) {
                for (x += j; j < x && k < 255; j++) {
                    buf[k++] = j;
                }
                break;
            }
        }
        if(tp == KJ_END) return NULL;  // 找不到对应的参数
        if (k == 255) return NULL; // 溢出
    }
    meta_t* pNewMeta = malloc((k + 1) * sizeof(meta_t));
    if(pNewMeta == NULL) return NULL;
    for(int i = 0; i < k; i++)
        *(pNewMeta + i) = *(pOrgMeta + buf[i]);
    *(pNewMeta + k) = KJ_END;
    return pNewMeta;
}
meta_t* ZqMetasFind(const meta_t* pOrgMeta, const char* key)
{
    meta_t* metas = (meta_t*)pOrgMeta;
    short tp = 0;

    while ((tp = (short)*metas) != KJ_END) {
        char* name = (char*)(*(metas + 1));
        int x = 2;
        if (tp == KJ_OBJ || tp == KJ_POBJ)
            x++;
        else if (tp == KJ_LIST || tp == KJ_PLIST)
            x = KgArrayGetNextMeta(metas + x) - metas;
        if (strcmp(key, name) == 0) return metas;
        metas += x;
    }

    return NULL;  // 找不到对应的参数
}

